package lk.icta.core.service.impl;

import lk.icta.common.AppConstants;
import lk.icta.common.ELandRuntimeException;
import lk.icta.common.ErrorCodes;
import lk.icta.common.dto.WorkBenchItem;
import lk.icta.core.dao.*;
import lk.icta.core.entity.*;
import lk.icta.core.service.LandManagementService;
import lk.icta.core.service.WorkflowService;
import lk.icta.user.entity.User;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

/**
 * @author Mahesha Kalpanie
 */
public class WorkflowServiceImpl implements WorkflowService {

    private static final Logger logger = LoggerFactory.getLogger(WorkflowServiceImpl.class);

    private LandApplicationDAO landApplicationDAO;
    private LandDAO landDAO;
    private KachcheryDAO kachcheryDAO;
    private WorkflowDAO workflowDAO;
    private AlienationMethodDAO alienationMethodDAO;
    private AlienationRailwayDAO alienationRailwayDAO;

    private LandManagementService landManagementService;
    // public static final Map<Enum<WorkflowTask>, List<LandApplication>> workItemList =
    //    new HashMap<Enum<WorkflowTask>, List<LandApplication>>();

    //workflow start node for all alienation methods
    public static final int START_NODE = 1;

    public WorkflowServiceImpl(LandApplicationDAO landApplicationDAO, LandDAO landDAO, KachcheryDAO
            kachcheryDAO, WorkflowDAO workflowDAO, AlienationMethodDAO alienationMethodDAO,
                               LandManagementService landManagementService, AlienationRailwayDAO alienationRailwayDAO) {
        this.landApplicationDAO = landApplicationDAO;
        this.landDAO = landDAO;
        this.kachcheryDAO = kachcheryDAO;
        this.workflowDAO = workflowDAO;
        this.alienationMethodDAO = alienationMethodDAO;
        this.landManagementService = landManagementService;
        this.alienationRailwayDAO = alienationRailwayDAO;
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> getApplicationsByState(User user, WorkflowTask state) {
        return landApplicationDAO.getApplicationsByState(user, state);
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> getApplicationsByStateSet(User user, EnumSet<WorkflowTask> stateSet) {
        logger.debug("get Applications by Sate set : ", user.getUsername());
        return landApplicationDAO.getApplicationsByStates(user, stateSet);
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> loadAppList(User user, WorkflowTask workflowAction) {
        List<Integer> workItemListByRoleAndTask = getWorkflowItemListByUserRoleAndTask(user.getRole().getId(), workflowAction);
        return landApplicationDAO.getPendingApplicationsByWorkflowTask(user, workItemListByRoleAndTask);
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> loadAppListUseAlienationMethod(User user, WorkflowTask workflowAction, int alienationMethodId) {
        List<Integer> workItemListByRoleAndTask = getWorkflowItemListByUserRoleAndTask(user.getRole().getId(), workflowAction);
        return landApplicationDAO.getPendingApplicationsByWorkflowTaskByAlienationMethod(user, workItemListByRoleAndTask, alienationMethodId);
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<WorkBenchItem> loadWorkBench(User user) {
        logger.debug("Loading Workbench : {} - {}", user.getUsername(), user.getRole().getId());

        List<LandApplication> landApps = null;
        List<Land> landList = null;
        List<AlienationRailway> alienationRailwayList = null;
        List<Kachchery> kachcheryList = null;
        List<WorkBenchItem> workBenchItemList = new ArrayList<WorkBenchItem>();


        //find all outstanding applications for the user
        //landApps = landApplicationDAO.getApplicationsByWorkItemList(user, workItemListByRole);


        List<Integer> workItemListByRole = getWorkflowItemListByUserRole(user.getRole().getId());
        List applicationCountList = landApplicationDAO.getPendingApplicationsCountByWorkflowTask(user, workItemListByRole);

        AlienationMethod alienationMethod = null;
        Object[] result = null;
        WorkflowTask task = null;
        int alienationMethodId = 0;
        long count;

        if (applicationCountList != null) {
            for (Object anApplicationCount : applicationCountList) {
                result = (Object[]) anApplicationCount;
                task = (WorkflowTask) result[0];
                if (result[2] != null) {
                    alienationMethodId = Integer.parseInt(result[2].toString());
                }
                count = (Long) result[1];
                if (count > 0) {
                    if (alienationMethodId != 0) {
                        alienationMethod = alienationMethodDAO.getAlienationMethodById(alienationMethodId, user);
                    }
                    if (alienationMethod != null) {
                        //workBenchItemList.add(populateWorkbench((int) count, task, AppConstants.LOAD_APP_LIST_ACTION, alienationMethod.getEnName()));

                        // workBenchItemList.add(populateWorkbench((int) count, task, AppConstants.LOAD_APP_LIST_ACTION, alienationMethod.getEnName(),alienationMethodId));
                        workBenchItemList.add(populateWorkbench((int) count, task, AppConstants.LOAD_APP_LIST_ACTION_USE_ALIENATION_METHOD, alienationMethod.getEnName(), alienationMethodId));
                    } else {
                        workBenchItemList.add(populateWorkbench((int) count, task, AppConstants.LOAD_APP_LIST_ACTION, null, -1));
                    }

                }
                logger.debug("Loading Workbench Alienation method id is: {} and method {} ", alienationMethodId, alienationMethod);
            }
        }

        /*  landApps = landApplicationDAO.getApplicationsByState(user, LandApplication.State.SIGNED_ALIENATION_DOCUMENT_APPROVED);

                             if (landApps != null && landApps.size() != 0) {
                                 workBenchItemList.add(populateWorkbenchItem(landApps.size(), ModuleType.INFORM_REC_APP,
                                         AppConstants.GRANTED,
                                         AppConstants.LOAD_INFORM_REC_APP_LIST));
                             }


        */
        if (AppConstants.ORDS_USER_ROLE.equals(user.getRole().getId())) {
            //Show Detail Lands to be approved
            // landList = landDAO.getActiveLandsByGNDivisionListAndState(user, Land.ApprovalState.PENDING, Land.Mode.DETAIL);
            landList = landDAO.getActivePendingLandsByDSDivision(user);
            if (landList != null && landList.size() != 0) {
                workBenchItemList.add(populateWorkbenchItem(landList.size(), ModuleType.DETAILED_LAND,
                        AppConstants.APPROVED, AppConstants.LOAD_LAND_LIST_TO_BE_APPROVED_ACTION));
            }

            //Associate Land
            landList = landManagementService.getAllLandAssociationsToBeApprovedByUser(user);
            if (landList != null && landList.size() != 0) {
                workBenchItemList.add(populateWorkbenchItem(landList.size(), ModuleType.LAND_ASSOCIATION,
                        AppConstants.APPROVED, AppConstants.LOAD_ASSOCIATE_LAND_LIST_TO_BE_APPROVED_ACTION));
            }

            //Define AM Land
            landList = landManagementService.getAllLandDefineAMAssociationsToBeApprovedByUser(user);
            if (landList != null && landList.size() != 0) {
                workBenchItemList.add(populateWorkbenchItem(landList.size(), ModuleType.DEFINE_AM,
                        AppConstants.APPROVED, AppConstants.LOAD_DEFINE_AM_LAND_LIST_TO_BE_APPROVED_ACTION));
            }

            //Kachchery to be Approved
            kachcheryList = kachcheryDAO.getAllKachcheryByDSDivisionAndState(Kachchery.Status.PENDING, user);
            if (kachcheryList != null && kachcheryList.size() != 0) {
                workBenchItemList.add(populateWorkbenchItem(kachcheryList.size(), ModuleType.LAND_KACHCHERY,
                        AppConstants.APPROVED, AppConstants.LOAD_LAND_KACHCHERY_LIST_TO_BE_APPROVED_ACTION));
            }

            //Kachchery reject list
            kachcheryList = kachcheryDAO.getAllKachcheryByDSDivisionAndState(Kachchery.Status.REJECT_PLC, user);
            if (kachcheryList != null && kachcheryList.size() != 0) {
                workBenchItemList.add(populateWorkbenchItem(kachcheryList.size(), ModuleType.LAND_KACHCHERY,
                        AppConstants.REJECTED, AppConstants.LOAD_LAND_KACHCHERY_LIST_REJECT_ACTION));
            }

            //Approve sub divided land
            landList = landDAO.getSubDividedLandsTobeApproveByDSDivision(user);
            if (landList != null && landList.size() != 0) {
                workBenchItemList.add(populateWorkbenchItem(landList.size(), ModuleType.SUB_DIVIDED_LAND,
                        AppConstants.APPROVED, AppConstants.LOAD_SUB_DIVIDED_LAND_LIST_TO_BE_APPROVED_ACTION));
            }

            //initial apps to be approved
            landApps = landApplicationDAO.getInitialApplicationsByState(user,
                    LandApplication.State.INITIAL_APPLICATION_DATA_ENTRY);
            if (landApps != null && landApps.size() != 0) {
                workBenchItemList.add(populateWorkbenchItem(landApps.size(), ModuleType.INITIAL_APP,
                        AppConstants.APPROVED,
                        AppConstants.LOAD_INITIAL_APP_LIST_TO_BE_APPROVED_ACTION));
            }
        } else if (AppConstants.LO_USER_ROLE.equals(user.getRole().getId())) {

            //rejected Land list
            landList = landDAO.getRejectedLandsByDSDivision(user);
            if (landList != null && landList.size() != 0) {
                workBenchItemList.add(populateWorkbenchItemDefault(landList.size(), ModuleType.DETAILED_LAND,
                        AppConstants.REJECTED, AppConstants.LOAD_REJECTED_LAND_LIST_ACTION));
            }

            landApps = landApplicationDAO.getInitialApplicationsByState(user, LandApplication.State.INITIAL_APPLICATION_APPROVED);
            if (landApps != null && landApps.size() != 0) {
                workBenchItemList.add(populateWorkbenchItemOfLO(landApps.size(), ModuleType.INITIAL_APP,
                        AppConstants.APPROVED,
                        AppConstants.LOAD_INITIAL_APPROVED_APP_LIST_ACTION));
            }

            landApps = landApplicationDAO.getInitialApplicationsByState(user, LandApplication.State.INITIAL_APPLICATION_REJECTED);
            if (landApps != null && landApps.size() != 0) {
                workBenchItemList.add(populateWorkbenchItemOfLO(landApps.size(), ModuleType.INITIAL_APP,
                        AppConstants.REJECTED,
                        AppConstants.LOAD_INITIAL_REJECTED_APP_LIST_ACTION));
            }

            //Kachchery reject list
            kachcheryList = kachcheryDAO.getAllKachcheryByDSDivisionAndState(Kachchery.Status.REJECT_ORDS, user);
            if (kachcheryList != null && kachcheryList.size() != 0) {
                workBenchItemList.add(populateWorkbenchItem(kachcheryList.size(), ModuleType.LAND_KACHCHERY,
                        AppConstants.REJECTED, AppConstants.LOAD_LAND_KACHCHERY_LIST_REJECT_ACTION));
            }

            //Kachchery attach Doc list
            kachcheryList = kachcheryDAO.getAllKachcheryByDSDivisionAndState(Kachchery.Status.APPROVE_ORDS, user);
            if (kachcheryList != null && kachcheryList.size() != 0) {
                workBenchItemList.add(populateWorkbenchItem(kachcheryList.size(), ModuleType.LAND_KACHCHERY,
                        AppConstants.ATTACHED, AppConstants.LOAD_LAND_KACHCHERY_LIST_ATTACH_DOC));
            }

        } else if (AppConstants.PLC_USER_ROLE.equals(user.getRole().getId())) {

            //Kachchery to be Approved
            kachcheryList = kachcheryDAO.getAllKachcheryByDSDivisionAndState(Kachchery.Status.ATTACH_DOC_LO, user);
            if (kachcheryList != null && kachcheryList.size() != 0) {
                workBenchItemList.add(populateWorkbenchItem(kachcheryList.size(), ModuleType.LAND_KACHCHERY,
                        AppConstants.APPROVED, AppConstants.LOAD_LAND_KACHCHERY_LIST_TO_BE_APPROVED_ACTION));
            }

        } else if (AppConstants.SC_USER_ROLE.equals(user.getRole().getId())) {
            logger.debug("SC");
            //landList = landDAO.getActivePendingLandsByDSDivision(user);
            EnumSet<AlienationRailway.State> stateSet = EnumSet.of(AlienationRailway.State.REJECTED_BY_BO);

            alienationRailwayList = alienationRailwayDAO.getAlienationRailwayByStateSet(user, stateSet);

            if (alienationRailwayList != null && alienationRailwayList.size() != 0) {
                workBenchItemList.add(populateWorkbenchItem(alienationRailwayList.size(), ModuleType.LAND,
                        AppConstants.REJECTED, AppConstants.LOAD_LAND_LIST_TO_BE_APPROVED_ACTION));
            }
        } else if (AppConstants.BO_USER_ROLE.equals(user.getRole().getId())) {
            logger.debug("BO");
            //landList = landDAO.getActivePendingLandsByDSDivision(user);
            EnumSet<AlienationRailway.State> stateSet = EnumSet.of(AlienationRailway.State.DATA_ENTRY);

            alienationRailwayList = alienationRailwayDAO.getAlienationRailwayByStateSet(user, stateSet);

            if (alienationRailwayList != null && alienationRailwayList.size() != 0) {
                workBenchItemList.add(populateWorkbenchItem(alienationRailwayList.size(), ModuleType.LAND,
                        AppConstants.APPROVED, AppConstants.LOAD_LAND_LIST_TO_BE_APPROVED_ACTION));
            }

            stateSet = EnumSet.of(AlienationRailway.State.REJECTED_BY_SH);

            alienationRailwayList = alienationRailwayDAO.getAlienationRailwayByStateSet(user, stateSet);

            if (alienationRailwayList != null && alienationRailwayList.size() != 0) {
                workBenchItemList.add(populateWorkbenchItem(alienationRailwayList.size(), ModuleType.LAND,
                        AppConstants.REJECTED, AppConstants.LOAD_LAND_LIST_TO_BE_APPROVED_ACTION));
            }

        } else if (AppConstants.SH_USER_ROLE.equals(user.getRole().getId())) {
            logger.debug("SH");
            //landList = landDAO.getActivePendingLandsByDSDivision(user);
            EnumSet<AlienationRailway.State> stateSet = EnumSet.of(AlienationRailway.State.APPROVED_BY_BO);

            alienationRailwayList = alienationRailwayDAO.getAlienationRailwayByStateSet(user, stateSet);

            if (alienationRailwayList != null && alienationRailwayList.size() != 0) {
                workBenchItemList.add(populateWorkbenchItem(alienationRailwayList.size(), ModuleType.LAND,
                        AppConstants.APPROVED, AppConstants.LOAD_LAND_LIST_TO_BE_APPROVED_ACTION));
            }

            stateSet = EnumSet.of(AlienationRailway.State.REJECTED_BY_SDH);

            alienationRailwayList = alienationRailwayDAO.getAlienationRailwayByStateSet(user, stateSet);

            if (alienationRailwayList != null && alienationRailwayList.size() != 0) {
                workBenchItemList.add(populateWorkbenchItem(alienationRailwayList.size(), ModuleType.LAND,
                        AppConstants.REJECTED, AppConstants.LOAD_LAND_LIST_TO_BE_APPROVED_ACTION));
            }
        } else if (AppConstants.SDH_USER_ROLE.equals(user.getRole().getId())) {
            logger.debug("SDH");
            //landList = landDAO.getActivePendingLandsByDSDivision(user);
            EnumSet<AlienationRailway.State> stateSet = EnumSet.of(AlienationRailway.State.APPROVED_BY_SH);

            alienationRailwayList = alienationRailwayDAO.getAlienationRailwayByStateSet(user, stateSet);

            if (alienationRailwayList != null && alienationRailwayList.size() != 0) {
                workBenchItemList.add(populateWorkbenchItem(alienationRailwayList.size(), ModuleType.LAND,
                        AppConstants.APPROVED, AppConstants.LOAD_LAND_LIST_TO_BE_APPROVED_ACTION));
            }

            stateSet = EnumSet.of(AlienationRailway.State.REJECTED_BY_DH);

            alienationRailwayList = alienationRailwayDAO.getAlienationRailwayByStateSet(user, stateSet);

            if (alienationRailwayList != null && alienationRailwayList.size() != 0) {
                workBenchItemList.add(populateWorkbenchItem(alienationRailwayList.size(), ModuleType.LAND,
                        AppConstants.REJECTED, AppConstants.LOAD_LAND_LIST_TO_BE_APPROVED_ACTION));
            }

        } else if (AppConstants.DH_USER_ROLE.equals(user.getRole().getId())) {
            logger.debug("DH");
            //landList = landDAO.getActivePendingLandsByDSDivision(user);
            EnumSet<AlienationRailway.State> stateSet = EnumSet.of(AlienationRailway.State.APPROVED_BY_SDH);

            alienationRailwayList = alienationRailwayDAO.getAlienationRailwayByStateSet(user, stateSet);

            if (alienationRailwayList != null && alienationRailwayList.size() != 0) {
                workBenchItemList.add(populateWorkbenchItem(alienationRailwayList.size(), ModuleType.LAND,
                        AppConstants.APPROVED, AppConstants.LOAD_LAND_LIST_TO_BE_APPROVED_ACTION));
            }
        }


        return workBenchItemList;
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> loadAppListBeforeAlienation(User user, int mode) {
        logger.debug("Load Land Application List : {} ", user.getUsername());
        //Find All Active Land Apps with States in WorkflowTask
        List<LandApplication> landApplicationList = new ArrayList<LandApplication>();
        //Load all apps to be completed for current user group   (State.DETAILED_FORM_DATA_ENTRY)
        try {
            List<LandApplication> landApps = null;
            if (mode == 3) {
                landApps = landApplicationDAO.getApplicationsByState(user, WorkflowTask.DETAILED_FORM_DATA_ENTRY);
            } else if (mode == 4) {
                landApps = landApplicationDAO.getApplicationsByState(user, WorkflowTask.DETAILED_FORM_APPROVED);
            } else if (mode == 5) {
                //landApps = landApplicationDAO.getApplicationsByState(user, LandApplication.State.DETAILED_FORM_FINALIZED);
            }
            return landApps;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return landApplicationList;
    }

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> loadApprovedDetailedAppList(User user) {
        logger.debug("Load Land Application List : {} ", user.getUsername());
        //Find All Active Land Apps with States in WorkflowTask
        List<LandApplication> landApplicationList = new ArrayList<LandApplication>();
        //Load all apps to be completed for current user group   (State.DETAILED_FORM_DATA_ENTRY)
        try {
            return landApplicationDAO.getApplicationsByState(user, WorkflowTask.DETAILED_FORM_APPROVED);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return landApplicationList;
    }


    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> loadFinalizedAppList(User user, int mode) {
        logger.debug("Load Land Application List : {} ", user.getUsername());
        //Find All Active Land Apps with States in WorkflowTask
        List<LandApplication> landApplicationList = new ArrayList<LandApplication>();
        //Load all apps to be completed for current user group   (State.DETAILED_FORM_DATA_ENTRY)
        try {
            List<LandApplication> landApps = null;
            landApps = landApplicationDAO.getApplicationsByState(user, WorkflowTask.DETAILED_FORM_FINALIZED);
            return landApps;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return landApplicationList;
    }

    public WorkflowItem getWorkflowItemById(int id) {
        return workflowDAO.getWorkflowItemById(id);
    }

    public WorkflowItem getWorkflowStartItemById() {
        return workflowDAO.getWorkflowItemById(START_NODE);
    }

//    public WorkflowItem getStartItemOfWorkflow(int alienationMethodId) {
//        return workflowDAO.getStartItemOfWorkflow(alienationMethodId);
//    }

    //find work item  by task from next work item list
    public WorkflowItem getNextWorkflowItemByTask(WorkflowTask workflowTask, String nextItemList) {
        StringTokenizer st = new StringTokenizer(nextItemList, ",");
        int nextItemId = 0;
        WorkflowItem nextItem = null;
        while (st.hasMoreTokens()) {
            //System.out.println();
            nextItemId = Integer.parseInt(st.nextToken());
            if (getWorkflowItemById(nextItemId).getWorkflowTask() == workflowTask) {
                nextItem = getWorkflowItemById(nextItemId);
                break;

            }
        }
        return nextItem;
    }

    private void handleELandRuntimeException(String message, int code) {
        logger.error(message);
        throw new ELandRuntimeException(message, code);
    }

    public WorkflowItem getNextWorkflowItem(WorkflowTask workflowTask, int currentItemId, User user) {
        //todo check workflow id and role permissions. wf id of current id should exist in wf id list of next item
        WorkflowItem currentItem = getWorkflowItemById(currentItemId);
        logger.debug("Current workflow item id {} -", currentItemId);
        logger.debug("Current workflow item {} - ", currentItem.getWorkflowTask());
        logger.debug("Current workflow item role list {} - ", currentItem.getUserRole());
        logger.debug("Current workflow item - next item list {} -", currentItem.getNextItemId());
        StringTokenizer st = new StringTokenizer(currentItem.getNextItemId(), ",");
        int nextItemId = 0;
        WorkflowItem nextItem = null;
        while (st.hasMoreTokens()) {
            nextItemId = Integer.parseInt(st.nextToken());
            if (getWorkflowItemById(nextItemId).getWorkflowTask() == workflowTask) {
                nextItem = getWorkflowItemById(nextItemId);
                break;
            }
        }
        if (nextItem == null) {
            handleELandRuntimeException(user.getFullName() + " can not perform this invalid action",
                    ErrorCodes.INVALID_WORKFLOW);
        }
        //TODO:
        //intoduce new columns to alienation method table - start wf item, end , skip
        //1. find item by alienationmethod, action and role  (in AM range filter by role and action) (valid action)
        //2. check whether this is the next item with respect to current item (verify correct order)
        return nextItem;
    }

    public WorkflowItem getNextWorkflowItemByUserRole(int currentItemId, User user) {
        //todo check workflow id and role permissions. wf id of current id should exist in wf id list of next item
        WorkflowItem currentItem = getWorkflowItemById(currentItemId);
        logger.debug("Current workflow item id {} -", currentItemId);
        logger.debug("Current workflow item {} - ", currentItem.getWorkflowTask());
        logger.debug("Current workflow item role list {} - ", currentItem.getUserRole());
        logger.debug("Current workflow item - next item list {} -", currentItem.getNextItemId());
        StringTokenizer st = new StringTokenizer(currentItem.getNextItemId(), ",");
        StringTokenizer stRoles = null;
        int nextItemId = 0;
        WorkflowItem nextItem = null;
        while (st.hasMoreTokens()) {
            nextItemId = Integer.parseInt(st.nextToken());
            //if (getWorkflowItemById(nextItemId).getWorkflowTask() == workflowTask) {
            //   logger.debug("user role ---- {}", user.getRole().getId());
            //  logger.debug("user role of workflow ----{}", getWorkflowItemById(nextItemId).getUserRole());
            if (nextItemId != 0) {
                String nextRoleList = getWorkflowItemById(nextItemId).getUserRole();

                if (contains(nextRoleList, user.getRole().getId())) {
                    nextItem = getWorkflowItemById(nextItemId);
                    break;
                }
            }

           /* stRoles = new StringTokenizer(getWorkflowItemById(nextItemId).getUserRole(), ",");
            while (stRoles.hasMoreTokens()) {
               if (user.getRole().getId().equals(Integer.parseInt(stRoles.nextToken())){
                    nextItem = getWorkflowItemById(nextItemId);
                    break;
                }
            }     */
        }
        return nextItem;
    }


    private boolean contains(String str, String value) {
        StringTokenizer st = new StringTokenizer(str, ",");
        while (st.hasMoreTokens()) {
            if (st.nextToken().equals(value)) {
                return true;
            }
        }
        return false;
    }

    //find work items of which the next items own to the given user role
    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<Integer> getWorkflowItemListByUserRole(String role) {

        logger.debug("User Role is {} ", role);

        Map<Integer, WorkflowItem> allItems = workflowDAO.getAllWorkflowItems();
        List<Integer> nextWorkItemsByRole = new ArrayList<Integer>();

        //find all work items by user role
        List<Integer> workItemsByRole = new ArrayList<Integer>();
        for (Map.Entry<Integer, WorkflowItem> entry : allItems.entrySet()) {
            if (contains(entry.getValue().getUserRole(), role)) {
                workItemsByRole.add(entry.getKey());
            }
        }

        logger.debug("Work item for role {} are {} ", role, workItemsByRole.toString());

        //find work items of which the next item list contains the above work item (items by user role)
        if (!workItemsByRole.isEmpty()) {
            for (Map.Entry<Integer, WorkflowItem> entry : allItems.entrySet()) {
                for (Integer workItemId : workItemsByRole) {
                    if (contains(entry.getValue().getNextItemId(), workItemId.toString())) {
                        nextWorkItemsByRole.add(entry.getKey());
                        //  logger.debug("next Work item ---------- {}", entry.getValue().getNextItemId());
                        // logger.debug("Work item id ---------- {}", workItemId.toString());
                        break;
                    }
                }
            }
        }
        return nextWorkItemsByRole;
    }

    //find work items of which the next items own to the given user role
    public List<Integer> getWorkflowItemListByUserRoleAndTask(String role, WorkflowTask task) {

        Map<Integer, WorkflowItem> allItems = workflowDAO.getAllWorkflowItems();
        List<Integer> nextWorkItemsByRole = new ArrayList<Integer>();

        //find all work items by user role
        List<Integer> workItemsByRole = new ArrayList<Integer>();
        for (Map.Entry<Integer, WorkflowItem> entry : allItems.entrySet()) {
            if (contains(entry.getValue().getUserRole(), role)) {
                workItemsByRole.add(entry.getKey());
            }
        }

        //find work items of which the next item list contains the above work item (items by user role)
        if (!workItemsByRole.isEmpty()) {
            for (Map.Entry<Integer, WorkflowItem> entry : allItems.entrySet()) {
                for (Integer workItemId : workItemsByRole)
                    if (contains(entry.getValue().getNextItemId(), workItemId.toString()) && entry.getValue().getWorkflowTask() == task) {
                        nextWorkItemsByRole.add(entry.getKey());
                    }
            }
        }
        return nextWorkItemsByRole;
    }


    /*@Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> loadAppList(User user, String workflowAction) {
        logger.debug("Load Land Application List : {} ", user.getUsername());
        //Find All Active Land Apps with States in WorkflowTask
        List<LandApplication> landApplicationList = new ArrayList<LandApplication>();
        //Load all apps to be completed for current user group   (State.DETAILED_FORM_DATA_ENTRY)
        try {
            List<LandApplication> landApps = null;

//            landApps = landApplicationDAO.getApplicationsByState(user, LandApplication.State.DETAILED_FORM_FINALIZED);
            landApps = landApplicationDAO.getApplicationsByState(user, WorkflowTask.APPROVE_ACCEPTED_AND_COMPLETED_APPLICATION);
            if (landApps != null) {
                for (LandApplication landApp : landApps) {
                    // WorkflowTask nextState = landApp.findNextState(); // May be approve or rejected

                    int nextItemId = 0; //TODO; landApp.getWorkflowItem().getNextItemId();
                    WorkflowItem nextItem = getWorkflowItemById(nextItemId);

                    if (nextItem != null && nextItem.getUserRole().equals(user.getRole().getId())) {
                        if (nextItem.getWorkflowTask().getAction().equals(workflowAction)) {
                            landApplicationList.add(landApp);
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return landApplicationList;
    }*/

    @Transactional(propagation = Propagation.NEVER, readOnly = true)
    public List<LandApplication> loadRejectedAppList(User user) {
        logger.debug("Load Land Rejected Application List : {} ", user.getUsername());
        //Find All Active Land Apps with States in WorkflowTask
        List<LandApplication> landApplicationList = new ArrayList<LandApplication>();
        //Load all apps to be completed for current user group   (State.DETAILED_FORM_DATA_ENTRY)
        try {
            List<LandApplication> landApps = null;

            /* landApps = landApplicationDAO.getApplicationsByStateSet(user, WorkflowTask.REJECTED_BY_LCG,
            WorkflowTask.REJECTED_BY_MINISTRY);*/
            landApps = landApplicationDAO.getApplicationsByWorkflowTask(user, WorkflowTask.REJECTED);

            //  if (landApps != null) {
            if (AppConstants.PLC_USER_ROLE.equals(user.getRole().getId())) {
                return landApps;
            } else if (AppConstants.LCG_USER_ROLE.equals(user.getRole().getId())) {

                for (LandApplication landApp : landApps) {
                    if (AppConstants.ORLP_USER_ROLE.equals(landApp.getWorkflowItem().getUserRole())) {
                        landApplicationList.add(landApp);
                    }
                }

            }
            // }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return landApplicationList;
    }


    private WorkBenchItem populateWorkbenchItem(int size, ModuleType module,
                                                String workflowAction, String action) {
        // logger.debug("populating work bench");
        WorkBenchItem workBenchItem = new WorkBenchItem();
        workBenchItem.setDescription(module.getName() + " to be " + workflowAction);
        workBenchItem.setCount(size);
        workBenchItem.setAction(action);
        workBenchItem.setWorkflowAction(workflowAction);
        return workBenchItem;
    }

    private WorkBenchItem populateWorkbench(int size, WorkflowTask workflowTask, String workflowAction, String alienationMethod, int alienationMethodId) {
        // logger.debug("populating work bench");

        WorkBenchItem workBenchItem = new WorkBenchItem();
        if (alienationMethod != null) {
            workBenchItem.setDescription(alienationMethod + "  -  " + workflowTask.getAction());
        } else {
            workBenchItem.setDescription(workflowTask.getAction());
        }
        workBenchItem.setCount(size);
        workBenchItem.setAction(workflowAction);
        workBenchItem.setWorkflowTask(workflowTask);
        workBenchItem.setAlienationMethodId(alienationMethodId);
        //workBenchItem.setWorkflowAction(workflowAction);
        return workBenchItem;
    }


    private WorkBenchItem populateWorkbenchItemOfLO(int size, ModuleType module,
                                                    String workflowAction, String action) {
        //   logger.debug("populating work bench");
        WorkBenchItem workBenchItem = new WorkBenchItem();
        workBenchItem.setDescription("Generate letters for " + workflowAction + " " + module.getName());
        workBenchItem.setCount(size);
        workBenchItem.setAction(action);
        workBenchItem.setWorkflowAction(workflowAction);
        return workBenchItem;
    }

    private WorkBenchItem populateWorkbenchItemDefault(int size, ModuleType module,
                                                       String workflowAction, String action) {
        // logger.debug("populating work bench");
        WorkBenchItem workBenchItem = new WorkBenchItem();
        workBenchItem.setDescription(module.getName() + " - " + workflowAction);
        workBenchItem.setCount(size);
        workBenchItem.setAction(action);
        workBenchItem.setWorkflowAction(workflowAction);
        return workBenchItem;
    }

    private WorkBenchItem populateRejectedItem(int size, ModuleType module,
                                               String workflowAction, String action) {
        //  logger.debug("populating work bench");
        WorkBenchItem workBenchItem = new WorkBenchItem();
        workBenchItem.setDescription("Rejected " + module.getName());
        workBenchItem.setCount(size);
        workBenchItem.setAction(action);
        workBenchItem.setWorkflowAction(workflowAction);
        return workBenchItem;
    }


}
